#include <unistd.h>

#include <sstream>

#include "sha256.hpp"

sha256::sha256(): p_ctx__( nullptr )
{
    p_ctx__ = EVP_MD_CTX_new();
    EVP_DigestInit_ex(p_ctx__, EVP_sha256(), nullptr);
}

sha256 :: ~sha256()
{
    if( p_ctx__ ){
        EVP_MD_CTX_free( p_ctx__ );
    }
}


sha256 :: sha256( const std::string& data ): p_ctx__( nullptr )
{
    p_ctx__ = EVP_MD_CTX_new();
    EVP_DigestInit_ex(p_ctx__, EVP_sha256(), nullptr);

    update( data.c_str() , data.length() );
}

sha256 :: sha256( void * data , size_t len ): p_ctx__( nullptr )
{
    p_ctx__ = EVP_MD_CTX_new();
    EVP_DigestInit_ex(p_ctx__, EVP_sha256(), nullptr);

    update( data , len );
}

void sha256 :: update( const void * data , size_t len )
{
    EVP_DigestUpdate( p_ctx__, data, len );
}

std::string sha256 :: finish()
{
    std::string ret;
    unsigned char hash[EVP_MAX_MD_SIZE];
    char hash_str[ 2 * EVP_MAX_MD_SIZE ];
    uint32_t hashSize = 0;

    int rc = EVP_DigestFinal_ex(p_ctx__, hash, &hashSize);
    if( rc != 0 ){
        return ret;
    }

    for( uint32_t i = 0; i < hashSize; ++i ){
        sprintf( hash_str + ( i << 1 ) , "%02X" , hash[i] );
    }
    return ret;
}
